package cn.plem;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.concurrent.Executors;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.ws.rs.Path;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Main extends ClassLoader implements HttpHandler {

	private HttpServer server;

	public static void main(String[] args) throws Exception {
		new Main(args.length == 0 ? 80 : Integer.parseInt(args[0]));
	}

	public Main(int port) throws Exception {
		InetSocketAddress ip = new InetSocketAddress(port);
		server = HttpServer.create(ip, 0);
		server.createContext("/", this);
		server.setExecutor(Executors.newCachedThreadPool());
		server.start();
		System.out.println(String.format("httpserver startup on %s ...", port));

		// createContext(WhoamiHandler.class.getName());
		createContext();
	}

	private void createContext() throws Exception {
		URL url = Thread.currentThread().getContextClassLoader().getResource("META-INF/MANIFEST.MF");

		JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
		Enumeration<JarEntry> entrys = jarFile.entries();
		while (entrys.hasMoreElements()) {
			String p = entrys.nextElement().getName();
			// System.out.println(p);
			if (p.endsWith("Handler.class")) {
				String name = p.substring(0, p.indexOf(".class")).replaceAll("\\\\|/", ".");
				createContext(name);
			}

		}
	}

	private void createContext(String name) throws Exception {
		// System.out.println(name);
		Class<HttpHandler> classes = (Class<HttpHandler>) this.loadClass(name);
		Path path = (Path) classes.getAnnotation(Path.class);
		if (path != null) {
			System.out.println(String.format("createContext:%s by %s", path.value(), classes.getName()));
			server.createContext(path.value(), classes.newInstance());
		}
	}

	@Override
	public void handle(HttpExchange exchange) throws IOException {
		int status = 200;
		byte[] b = "handler ".getBytes();
		String uri = exchange.getRequestURI().toString().substring(1);
		if (Paths.get(uri).toFile().exists()) {
			b = Files.readAllBytes(Paths.get(uri));
		} else {
			try {
				createContext(uri);
			} catch (Exception e) {
				// System.out.println(e.getMessage());
				status = 404;
				b = "404".getBytes();
			}
		}
		exchange.sendResponseHeaders(status, 0);
		try (OutputStream out = exchange.getResponseBody()) {
			out.write(b);
		}
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] b;
		try {
			b = Files.readAllBytes(Paths.get(String.format("classes/%s.class", name.replaceAll("\\.", "/"))));
		} catch (IOException e) {
			// System.out.println(e.getMessage());
			return Object.class;
		}
		return super.defineClass(name, b, 0, b.length);
	}

}
